/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>
#include <mc/common.h>
#include <mc/memory.h>
#include <smbus/smbus_postbox.h>

namespace {

// Mock SMBus class for testing
class MockSMBus : public dev::smbus {
public:
    MockSMBus(mc::engine::abstract_object* parent = nullptr) : dev::smbus(parent) {}

    // Mock control variables
    bool mock_send_success = true;
    bool mock_read_success = true;
    std::vector<uint8_t> mock_read_data;
    std::vector<uint8_t> mock_send_response;

    std::pair<bool, std::vector<uint8_t>> send(uint32_t offset, const std::string& data) {
        if (!mock_send_success) {
            return {false, {}};
        }
        return {true, mock_send_response};
    }

    std::pair<bool, std::vector<uint8_t>> read(uint32_t offset, uint32_t len) {
        if (!mock_read_success) {
            return {false, {}};
        }
        return {true, mock_read_data};
    }
};

// Test fixture
class SMBusPostboxTest : public ::testing::Test {
protected:
    void SetUp() override {
        m_postbox = mc::make_shared<dev::SMBusPostbox>();
        m_mock_smbus = mc::make_shared<MockSMBus>();
    }

    void TearDown() override {
        m_postbox.reset();
        m_mock_smbus.reset();
    }

    mc::shared_ptr<dev::SMBusPostbox> m_postbox;
    mc::shared_ptr<MockSMBus> m_mock_smbus;
};

// ========== 构造函数和析构函数测试 ==========

TEST_F(SMBusPostboxTest, Constructor_Default) {
    // 目标：验证 SMBusPostbox 可以正常构造（默认参数）
    dev::SMBusPostbox postbox(nullptr);
    EXPECT_TRUE(true); // 构造成功即通过
}

TEST_F(SMBusPostboxTest, Constructor_WithParent) {
    // 目标：验证 SMBusPostbox 可以正常构造（带父对象）
    mc::engine::abstract_object* dummy_parent = nullptr;
    dev::SMBusPostbox postbox(dummy_parent);
    EXPECT_TRUE(true); // 构造成功即通过
}

TEST_F(SMBusPostboxTest, Destructor) {
    // 目标：验证 SMBusPostbox 可以正常析构
    {
        dev::SMBusPostbox postbox(nullptr);
    }
    EXPECT_TRUE(true); // 析构成功即通过
}

// ========== 初始化和注册测试 ==========

TEST_F(SMBusPostboxTest, Init_ValidAddress) {
    // 目标：验证 init 方法可以正常设置数据寄存器地址
    uint8_t test_addr = 0x48;
    m_postbox->init(test_addr);
    EXPECT_TRUE(true); // 无异常即通过
}

TEST_F(SMBusPostboxTest, RegisterSMBus_ValidDevice) {
    // 目标：验证 registerSMBus 方法可以正常注册SMBus设备
    m_postbox->registerSMBus(m_mock_smbus);
    EXPECT_TRUE(true); // 无异常即通过
}

TEST_F(SMBusPostboxTest, RegisterSMBus_NullDevice) {
    // 目标：验证 registerSMBus 方法可以处理空设备指针
    m_postbox->registerSMBus(nullptr);
    EXPECT_TRUE(true); // 无异常即通过
}


// ========== sendRequest 测试 ==========

TEST_F(SMBusPostboxTest, SendRequest_EmptyName) {
    // 目标：验证 sendRequest 空名称参数校验
    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = ""; // 空名称
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_NoSMBus) {
    // 目标：验证 sendRequest 在未注册SMBus时的行为
    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital";
    request.opcode = 0x01;
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_WriteFailure) {
    // 目标：验证 sendRequest KEEP_DIGITAL 类型写失败路径
    m_postbox->registerSMBus(m_mock_smbus);
    m_mock_smbus->mock_send_success = false;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital";
    request.opcode = 0x01;
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_StatusFailure) {
    // 目标：验证 sendRequest KEEP_DIGITAL 类型状态失败路径
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);

    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, static_cast<uint8_t>(dev::SMBusPostboxProtocol::CMD_STATUS_ERR_REQUEST)}; // 错误状态
    m_mock_smbus->mock_send_response = {0x00};

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital";
    request.opcode = 0x01;
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;
    request.data_out = true;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

// ========== sendRequest 测试 - 边界情况 ==========

TEST_F(SMBusPostboxTest, SendRequest_UnsupportedDataType) {
    // 目标：验证 sendRequest 不支持的数据类型
    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_unsupported";
    request.data_type = static_cast<dev::SMBusPostboxProtocol::ConvertType>(99); // 不支持的类型

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

// ========== 工厂方法测试 ==========

TEST_F(SMBusPostboxTest, Create_FactoryMethod) {
    // 目标：验证 create 工厂方法可以正常创建对象
    auto postbox = dev::SMBusPostboxProtocol::create();
    EXPECT_TRUE(postbox != nullptr);
}


// ========== sendRequest KEEP_DIGITAL 测试 ==========

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_DataOut_False) {
    // 目标：验证 sendRequest KEEP_DIGITAL 类型 data_out=false 的情况
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, static_cast<uint8_t>(dev::SMBusPostboxProtocol::CMD_STATUS_SUCCESS)};

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital_no_data";
    request.opcode = 0x01;
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;
    request.data_out = false; // 不需要数据输出

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty()); // 应该返回空字符串
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_DataReadFailure) {
    // 目标：验证 sendRequest KEEP_DIGITAL 类型数据读取失败的情况
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    // 第一次读取（状态检查）成功
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, static_cast<uint8_t>(dev::SMBusPostboxProtocol::CMD_STATUS_SUCCESS)};

    // 创建新的mock状态用于第二次读取（数据读取）失败
    // 注意：这里我们通过重新设置mock数据来模拟状态变化
    m_mock_smbus->mock_read_success = false;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital_data_fail";
    request.opcode = 0x01;
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;
    request.data_out = true;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_WithMask) {
    // 目标：验证 sendRequest KEEP_DIGITAL 类型带掩码的情况
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital_mask";
    request.opcode = 0x01;
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;
    request.data_out = true;
    request.data_mask = 0x00FFFF00;

    auto result = m_postbox->sendRequest(request);
    // 主要验证没有崩溃
    EXPECT_TRUE(true);
}

// ========== sendRequest 各种数据类型的基本测试 ==========

TEST_F(SMBusPostboxTest, SendRequest_KeepAscii_Basic) {
    // 目标：验证 sendRequest KEEP_ASCII 类型的基本功能
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_ascii";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ASCII;
    request.data_out = true;
    request.data_len = 4;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_ArrayToAsciiBigEndian_Basic) {
    // 目标：验证 sendRequest ARRAY_TO_ASCII_BIGENDIAN 类型的基本功能
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_be";
    request.data_type = dev::SMBusPostboxProtocol::ARRAY_TO_ASCII_BIGENDIAN;
    request.data_out = true;
    request.data_len = 4;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_KeepArray_Basic) {
    // 目标：验证 sendRequest KEEP_ARRAY 类型的基本功能
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ARRAY;
    request.ex_data_out = 2; // nvlink_num
    request.data_len = 8; // item_bits

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

// ========== 扩展测试 - 提高覆盖率 ==========

TEST_F(SMBusPostboxTest, SendRequest_KeepAscii_MultiChunk) {
    // 目标：验证 sendRequest KEEP_ASCII 类型多块读取
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_ascii_multi";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ASCII;
    request.data_out = true;
    request.data_len = 10; // 10字节数据，需要3块读取（4+4+2）

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_ArrayToAsciiBigEndian_MultiChunk) {
    // 目标：验证 sendRequest ARRAY_TO_ASCII_BIGENDIAN 类型多块读取
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_be_multi";
    request.data_type = dev::SMBusPostboxProtocol::ARRAY_TO_ASCII_BIGENDIAN;
    request.data_out = true;
    request.data_len = 12; // 12字节数据，需要3块读取

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_ArrayToAsciiLittleEndian_MultiChunk) {
    // 目标：验证 sendRequest ARRAY_TO_ASCII_LITTLEENDIAN 类型多块读取
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_le_multi";
    request.data_type = dev::SMBusPostboxProtocol::ARRAY_TO_ASCII_LITTLEENDIAN;
    request.data_out = true;
    request.data_len = 8; // 8字节数据，需要2块读取

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_KeepArray_MultiItem) {
    // 目标：验证 sendRequest KEEP_ARRAY 类型多项目读取
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_multi";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ARRAY;
    request.ex_data_out = 10; // nvlink_num = 10
    request.data_len = 16; // item_bits = 16

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_KeepArray_SingleRegister) {
    // 目标：验证 sendRequest KEEP_ARRAY 类型单寄存器读取
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_single_reg";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ARRAY;
    request.ex_data_out = 4; // nvlink_num = 4，需要1个寄存器
    request.data_len = 8; // item_bits = 8

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(true); // 主要验证没有崩溃
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_CommandTimeout) {
    // 目标：验证 sendRequest KEEP_DIGITAL 命令超时
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    // 设置读取返回超时状态
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, 0x00}; // CMD_STATUS_NULL

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_timeout";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;
    request.data_out = true;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepAscii_CommandTimeout) {
    // 目标：验证 sendRequest KEEP_ASCII 命令超时
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, 0x00}; // CMD_STATUS_NULL

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_ascii_timeout";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ASCII;
    request.data_out = true;
    request.data_len = 4;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepArray_CommandTimeout) {
    // 目标：验证 sendRequest KEEP_ARRAY 命令超时
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, 0x00}; // CMD_STATUS_NULL

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_timeout";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ARRAY;
    request.ex_data_out = 2;
    request.data_len = 8;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepAscii_WriteFailure) {
    // 目标：验证 sendRequest KEEP_ASCII 写失败
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = false; // 写失败

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_ascii_write_fail";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ASCII;
    request.data_out = true;
    request.data_len = 4;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepArray_WriteFailure) {
    // 目标：验证 sendRequest KEEP_ARRAY 写失败
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = false; // 写失败

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_write_fail";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ARRAY;
    request.ex_data_out = 2;
    request.data_len = 8;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepDigital_ReadFailure) {
    // 目标：验证 sendRequest KEEP_DIGITAL 数据读取失败
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    // 状态检查成功，但数据读取失败
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, static_cast<uint8_t>(dev::SMBusPostboxProtocol::CMD_STATUS_SUCCESS)};

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_digital_read_fail";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_DIGITAL;
    request.data_out = true;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepAscii_ReadFailure) {
    // 目标：验证 sendRequest KEEP_ASCII 数据读取失败
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, static_cast<uint8_t>(dev::SMBusPostboxProtocol::CMD_STATUS_SUCCESS)};

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_ascii_read_fail";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ASCII;
    request.data_out = true;
    request.data_len = 4;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

TEST_F(SMBusPostboxTest, SendRequest_KeepArray_ReadFailure) {
    // 目标：验证 sendRequest KEEP_ARRAY 数据读取失败
    m_postbox->registerSMBus(m_mock_smbus);
    m_postbox->init(0x40);
    m_mock_smbus->mock_send_success = true;
    m_mock_smbus->mock_read_success = true;
    m_mock_smbus->mock_read_data = {0x04, 0x00, 0x00, 0x00, static_cast<uint8_t>(dev::SMBusPostboxProtocol::CMD_STATUS_SUCCESS)};

    dev::SMBusPostboxProtocol::RequestParams request;
    request.name = "test_array_read_fail";
    request.data_type = dev::SMBusPostboxProtocol::KEEP_ARRAY;
    request.ex_data_out = 2;
    request.data_len = 8;

    auto result = m_postbox->sendRequest(request);
    EXPECT_TRUE(result.empty());
}

} // namespace
